#ifndef GAME_WORLD_MODE_H
#define GAME_WORLD_MODE_H
#include "game_world.h"
#include "game_audio.h"
#include "game_sim_region.h"
#include "game_random.h"

struct game_mode_world;
struct entity_collision_volume_group;

struct pairwise_collision_rule {
    uint32 IDA;                           // 存储实体 A 的索引，用于标识实体 A
    uint32 IDB;                           // 存储实体 B 的索引，用于标识实体 B
    bool32 CanCollide;                    // 标记这两个实体是否应该发生碰撞
    pairwise_collision_rule *NextInHash;  // 指向哈希链表中的下一个规则，用于解决哈希冲突
};

struct particle_cel {
    real32 Density;
    v3 VelocityTimesDensity;
};

struct particle {
    v3 P;
    v3 dP;
    v3 ddP;
    v4 dColor;
    v4 Color;
    bitmap_id BitmapID;
};

struct game_mode_world {
    world *World;
    uint32 NextParticles;
    particle Particles[256];
#define PARTICLE_CEL_DIM 32
    particle_cel ParticleCels[PARTICLE_CEL_DIM][PARTICLE_CEL_DIM];

    real32 TypicalFloorHeight;

    // TODO: 我们是否应该允许分屏？

    // 摄像机当前跟随的实体索引。
    entity_id CameraFollowingEntityIndex;
    world_position CameraP;  // 相机的位置
    world_position LastCameraP;
    v3 CameraOffset;

    // 存储英雄面朝的方向
    // HeroFacingDirection: 用于表示英雄当前面朝的方向，通常用一个整数值表示，例如 0 = 向上，1 =
    // 向右，2 = 向下，3 = 向左。
    uint32 HeroFacingDirection;

    // 每米对应的像素数，表示从世界单位（米）转换为屏幕单位（像素）的比例
    real32 MetersToPixels;

    // TODO: 必须是 2 的幂
    // 用于存储碰撞规则的哈希表，包含 256 个桶，每个桶是链表头
    // 每个桶存储的是一个指向 `pairwise_collision_rule` 结构的指针
    pairwise_collision_rule *CollisionRuleHash[256];

    // 指向空闲的碰撞规则链表的指针，用于回收和重用碰撞规则
    // 当一个规则被移除时，它会被放回这个链表中，供后续使用
    pairwise_collision_rule *FirstFreeCollisionRule;

    // 定义不同类型的碰撞体群组，用于存储每个实体的碰撞体信息。

    // 空的碰撞体，用于表示没有碰撞信息的实体。
    // 用于不需要碰撞的实体。
    entity_collision_volume_group *NullCollision;

    // 剑的碰撞体，用于表示剑的碰撞信息。
    // 剑的实体会有一个特定的碰撞体，用来检测与其他物体的碰撞。
    entity_collision_volume_group *SwordCollision;

    // 楼梯的碰撞体，用于表示楼梯的碰撞信息。
    // 楼梯的碰撞体用于检测玩家与楼梯的交互，确保玩家能够正确的上下楼梯。
    entity_collision_volume_group *StairCollision;

    // 玩家角色的碰撞体，用于表示玩家的碰撞信息。
    // 玩家会有一个特定的碰撞体，用来与环境中的物体（例如墙壁、楼梯等）发生碰撞。
    entity_collision_volume_group *HeroHeadCollision;
    entity_collision_volume_group *HeroBodyCollision;
    entity_collision_volume_group *HeroGloveCollision;

    // 怪物的碰撞体，用于表示怪物的碰撞信息。
    // 怪物的实体将有自己的碰撞体，用于与玩家、环境或其他怪物发生碰撞。
    entity_collision_volume_group *MonstarCollision;

    // 伙伴（例如宠物）的碰撞体，用于表示伙伴的碰撞信息。
    // 伙伴的实体也有碰撞体，用于与环境或玩家发生碰撞。
    entity_collision_volume_group *FamiliarCollision;

    // 墙壁的碰撞体，用于表示墙壁的碰撞信息。
    // 墙壁实体的碰撞体用于确保玩家和其他实体不能穿透墙壁。
    entity_collision_volume_group *WallCollision;

    // 标准房间的碰撞体，用于表示标准房间的碰撞信息。
    // 标准房间的碰撞体用于确保玩家在房间内与墙壁、地面等物体发生碰撞。
    entity_collision_volume_group *FloorCollision;

    // 游戏中的时间变量，用于追踪游戏的时间流逝
    real32 Time;

    loaded_bitmap TestFont;

    random_series EffectsEntropy;
    random_series GameEntropy;

    // Entropy[熵]
    game_assets Assets;
    audio_state AudioState;
    playing_sound *Music;

    uint32 CreationBufferIndex;
    entity CreationBuffer[4];
    uint32 LastUsedEntityStorageIndex;
};
struct game_state;
struct render_group;
struct game_mode_world;

bool32 UpdateAndGameRenderWorld(game_state *GameState, game_mode_world *WorldMode,
                                transient_state *TranState, game_input *Input, game_assets *Assets,
                                render_group *RenderGroup, loaded_bitmap *DrawBuffer);
void PlayWorld(game_state *GameState, transient_state *TranState);
void PackEntityIntoWorld(world *World, sim_region *SimRegion, entity *Source, world_position At);
brain *GetOrAddBrain(sim_region *SimRegion, brain_id ID, brain_type Type);
void ExecuteBrain(game_state *GameState, render_group *RenderGroup, game_input *Input,
                  game_mode_world *WorldMode, sim_region *SimRegion, brain *Brain, real32 dt);
bool32 IsEqual(traversable_reference A, traversable_reference B);
void DeleteLowEntity(sim_region *Region, entity *Entity);
brain_id AddBrain(game_mode_world *WorldMode);
void AddMonster(game_mode_world *WorldMode, world_position P, traversable_reference StandingOn);
void AddSnakeSegment(game_mode_world *WorldMode, world_position P, traversable_reference StandingOn,
                     brain_id BrainID, uint16 SegmentIndex);
void MoveEntity(game_mode_world *WorldMode, sim_region *SimRegion, entity *Entity, real32 dt,
                v3 ddP);
#endif